#include "HerzeleidPrecompiled.hxx"
#include "HerzeleidBasicCamera.hxx"
using namespace HerzeleidRendererResourcesNamespaceImpl;

BasicCamera::BasicCamera()
{
	Standard::ZeroValue( &m_Position );
	Standard::ZeroValue( &m_Direction );
	Standard::ZeroValue( &m_View );
	Standard::ZeroValue( &m_Proj );
}

Void BasicCamera::GetViewMatrix( _Out_ DirectX::XMMATRIX *ViewMatrix )
{
	(*ViewMatrix) = m_View;
}

Void BasicCamera::GetProjectionMatrix( _Out_ DirectX::XMMATRIX *ProjMatrix )
{
	(*ProjMatrix) = m_Proj;
}

Void BasicCamera::SetViewParameters(
	_In_ DirectX::XMFLOAT3A *EyePosition,	// The camera position. 
	_In_ DirectX::XMFLOAT3A *LookPosition,	// The point position the camera looks at.
	_In_ DirectX::XMFLOAT3A *UpDirection	// The direction for up.
	)
{
	SetViewParameters(
		&DirectX::XMLoadFloat3A(EyePosition),
		&DirectX::XMLoadFloat3A(LookPosition),
		&DirectX::XMLoadFloat3A(UpDirection)
		);
}

Void BasicCamera::SetViewParameters(
	_In_ DirectX::XMVECTOR *EyePosition,	// The camera position. 
	_In_ DirectX::XMVECTOR *LookPosition,	// The point position the camera looks at.
	_In_ DirectX::XMVECTOR *UpDirection	// The direction for up.
	)
{
	m_Position = (*EyePosition);
	m_Direction =  DirectX::XMVector3Normalize(
		DirectX::XMVectorSubtract((*LookPosition), (*EyePosition))
		);
#if 1
	m_View = DirectX::XMMatrixLookAtLH(
		(*EyePosition), (*LookPosition),
		(*UpDirection)
		);
#else // Or we can do it manually

	// Axis

	auto ZAxis = m_Direction; // zaxis = dir
	auto XAxis = DirectX::XMVector3Normalize(
		DirectX::XMVector3Cross(
			(*UpDirection), ZAxis
			)
		); // xaxis = normalize ( cross (up, zaxis) )
	auto YAxis = DirectX::XMVector3Cross(
			ZAxis, XAxis
		); // yaxis = cross

	// Offset

	auto XOffset = -DirectX::XMVectorGetX(
		DirectX::XMVector3Dot(XAxis, m_Position)
		); // xoffset = -dot(xaxis, eye)
	auto YOffset = -DirectX::XMVectorGetX(
		DirectX::XMVector3Dot(YAxis, m_Position)
		); // yoffset = -dot(yaxis, eye)
	auto ZOffset = -DirectX::XMVectorGetX(
		DirectX::XMVector3Dot(ZAxis, m_Position)
		); // zoffset = -dot(zaxis, eye)

	// View

	m_View = DirectX::XMMatrixSet(
		DirectX::XMVectorGetX(XAxis), DirectX::XMVectorGetY(XAxis), DirectX::XMVectorGetZ(XAxis), XOffset,
		DirectX::XMVectorGetX(YAxis), DirectX::XMVectorGetY(YAxis), DirectX::XMVectorGetZ(YAxis), YOffset,
		DirectX::XMVectorGetX(ZAxis), DirectX::XMVectorGetY(ZAxis), DirectX::XMVectorGetZ(ZAxis), ZOffset,
		0.0f,						  0.0f,							0.0f,						  1.0f
		);

#endif

}

Void BasicCamera::SetProjectionParameters(
	_In_ Float32 fMinimumFieldOfView,
	_In_ Float32 fAspectRatio,
	_In_ Float32 fNearPlane,
	_In_ Float32 fFarPlane
	)
{
#if 1
	m_Proj = DirectX::XMMatrixPerspectiveFovLH(
		fMinimumFieldOfView, fAspectRatio,
		fNearPlane, fFarPlane
		);
#else // Or we can do it manually

	auto fMinScale = 1.0f / tan( fMinimumFieldOfView * DirectX::XM_PI / 360.0f );
	auto fXScale = 1.0f;
	auto fYScale = 1.0f;

	if (fAspectRatio < 1.0f)
	{
		fYScale = fMinScale * fAspectRatio;
		fXScale = fMinScale;
	}
	else
	{
		fXScale = fMinScale / fAspectRatio;
		fYScale = fMinScale;
	}

	auto fZScale = fFarPlane / ( fFarPlane - fNearPlane );

	m_Proj = DirectX::XMMatrixSet(
		fXScale,	0.0f,		0.0f,		0.0f,
		0.0f,		fYScale,	0.0f,		0.0f,
		0.0f,		0.0f,		fZScale,	-1 * fNearPlane * fZScale,
		0.0f,		0.0f,		0.0f,		0.0f
		);

#endif
}

